import sun.org.mozilla.javascript.internal.Token;

public class Parser implements IParser {

	private IScanner scan;

	private Token currentTerminal;

	public Parser(IScanner scan) {
		this.scan = scan;
		currentTerminal = scan.scan();
	}

	public Object parseProgram() {
		parseBlock();
		if (currentTerminal.kind != Token.EOL) {
			System.out.println("Tokens found after end of program");
		}
		return null;
	}

	private void parseBlock() {
		accept(Token.FUNCTION);
		parseName();
		accept(Token.KINDOF);
		parseIdentifier();// ????????????????????????????????//????
		if (currentTerminal.kind == Token.WITHPARAMS) {
			accept(Token.WITHPARAMS);
			parseDeclaration();
		}
		accept(Token.BEGIN);
		accept(Token.EOL);
		parseStatement();
		accept(Token.ENDFUNCTION);
		accept(Token.EOL);
	}

	private void parseName() {
		if (currentTerminal.kind == Token.MAIN) {
			accept(Token.Main);
		} else if (currentTerminal.kind == Token.LABEL) {
			accept(Token.Label);
		}
	}

	private void parseIdentifier() {

	}

	private void parseDeclaration() {
		while (currentTerminal.kind == Token.LET) {
			parseOneDeclaration();
		}
	}

	private void parseOneDeclaration() {
		switch (currentTerminal.kind) {
		case Token.LET:
			accept(Token.LET);
			parseName();
			parseType();
			accept(Token.EOL);
			break;
		default:
			System.out.println("let expected");
			break;
		}
	}

	private void parseType() {
		accept(Token.KINDOF);
		parseIdentifier();// ?????????????????????????????????///
		if ( currentTerminal.kind == Token.ARRAYOF ) {
			accept(Token.ARRAYOF);
			parseLiteral();// ?????????????????????????????????
		}
	}

	private void parseStatement() {
		while ( currentTerminal.kind == Token.LABEL || 
				currentTerminal.kind == Token.INTEGERLITERAL ||  
				currentTerminal.kind == Token.SIZEOF ||  
				currentTerminal.kind == Token.IF || 
				currentTerminal.kind == Token.WHILE ||
				currentTerminal.kind == Token.READ || 
				currentTerminal.kind == Token.WRITE ) {
			switch (currentTerminal.kind) {
			case Token.LABEL:
			case Token.INTEGERLITERAL:
			case Token.SIZEOF:
				parseExpression();
				accept(Token.EOL);
				break;

			case Token.IF:
				accept(Token.IF);
				parseExpression();
				accept(Token.DO);
				accept(Token.EOL);
				parseStatement();
				if (currentTerminal.kind == Token.ELSE) {
					accept(Token.ELSE);
					accept(Token.DO);
					accept(Token.EOL);
					parseStatement();
				}
				accept(Token.ENDIF);
				accept(Token.EOL);
				break;

			case Token.WHILE:
				accept(Token.WHILE);
				parseExpression();
				accept(Token.DO);
				accept(Token.EOL);
				parseStatement();
				accept(Token.ENDWHILE);
				accept(Token.EOL);
				break;

			case Token.READ:
				accept(Token.READ);
				parseExpression();
				accept(Token.EOL);
				break;

			case Token.WRITE:
				accept(Token.WRITE);
				parseExpression();
				accept(Token.EOL);
				break;

			default:
				System.out.println("Error in statement");
				break;
			}
		}
	}

	private void parseExpression() {
		if (currentTerminal.kind == Token.LET) {
			parseOneDeclaration();
		} else {
			parsePrimary();
		}
		while (currentTerminal.kind == int_oper
				|| currentTerminal.kind == bool_oper) {
			parseOperator();
			parsePrimary();
		}
	}

	private void parsePrimary() {
		switch (currentTerminal.kind) {
		case Token.LABEL:
			accept(Token.LABEL);
			while (currentTerminal.kind == int_oper || 
					currentTerminal.kind == bool_oper || 
					currentTerminal.kind == Token.AT) {
				if (currentTerminal.kind == int_oper
						|| currentTerminal.kind == bool_oper) {
					parseOperator();
				} else if (currentTerminal.kind == Token.AT) {
					accept(Token.AT);
					accept(Token.INTEGERLITERAL);
					while (currentTerminal.kind == int_oper
							|| currentTerminal.kind == bool_oper) {
						parseOperator();
						parseExpression();
					}
				}
			}
			break;

		case Token.INTEGERLITERAL:
			accept(Token.INTEGERLITERAL);
			break;

		case Token.SIZEOF:
			accept(Token.SIZEOF);
			parseName();
			break;

		default:
			System.out.println("Error in primary");
			break;
		}
	}

	private void parseOperator() {
		if (currentTerminal.kind == int_oper
				|| currentTerminal.kind == bool_oper) {
			accept(Token.int_oper);
			accept(Token.bool_oper);
		}
	}
}
